#pragma once
#include<iostream>
#include<unordered_map>
#include<vector>
#include<thread>
#include<mutex>
#include<memory>
#include<functional>
#include<errno.h>
#include<string.h>
#include<stdint.h>
#include<assert.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<sys/eventfd.h>
#include<time.h>
#include<sys/timerfd.h>
#include"Channel.hpp"
#include"Poller.hpp" 
#include"Log.hpp"

class EventLoop;//声明EventLoop类

//Timequeue模块
using Func_Task_Callback = std::function<void()>;
using Remove_Task_Callback = std::function<void()>;
class TimeTask{//定时任务
    private:
        uint64_t _id;//任务id
        uint32_t _delay;//延迟时间(超时时间)
        bool _canceled;//是否取消
        Func_Task_Callback _callback;//回调函数(处理上层业务)
        Remove_Task_Callback _remove_callback;//移除回调函数
    public:
        // static int _count;
        TimeTask(uint64_t id,uint32_t delay,const Func_Task_Callback &callback):_id(id),_delay(delay),_callback(callback),_canceled(false)
        { /*_count++; std::cout<<_count<<std::endl;*/ }
        ~TimeTask()
        {
            if(!_canceled)//如果定时任务被取消了，则不执行回调函数
                _callback(); 
            _remove_callback(); 
        }
        void SetCanceled()
        {
            _canceled = true;
        }
        void SetRemoveCallback(const Remove_Task_Callback &callback)
        {
            _remove_callback = callback;    
        }
        uint32_t GetDelay() const { return _delay; }
};

// int TimeTask::_count = 0;
//注意：timewheel里凡是要用到的EventLoop功能，都要先声明，然后在eventloop类下面的地方定义，否则会出现编译错误
class TimeWheel{//时间轮（管理所有定时任务TimeTask）
    private:
        using Shared_Ptr_TimeTask = std::shared_ptr<TimeTask>;
        using Weak_Ptr_TimeTask = std::weak_ptr<TimeTask>;
        uint32_t _size;//时间轮的容量
        int _pos;//当前指针位置
        std::vector<std::vector<Shared_Ptr_TimeTask>> _wheel;//时间轮
        std::unordered_map<uint64_t,Weak_Ptr_TimeTask> _time_task_map;//任务id与任务的映射

        EventLoop* _loop;
        int _timerfd;//定时器fd -- 读取计数器，触发定时器事件
        std::unique_ptr<Channel> _timefd_channel;//定时器事件发生的channel(封装的_timerfd)

    private:
        void RemoveTimeTaskFromMap(uint64_t id)
        {
            auto it = _time_task_map.find(id);
            if(it == _time_task_map.end())
                return;
            
            _time_task_map.erase(it);
        }
        uint64_t ReadTimefd()
        {
            uint64_t expirations;//过期时间
            ssize_t n = read(_timerfd,&expirations,sizeof(expirations));
            if(n < 0){
                LOG_ERR("read timerfd error");
                abort();
            }
            return expirations;   
        }
        void OnTimefdEvent()//定时执行事件
        {
            uint64_t expirations = ReadTimefd();
            for(int i = 0;i<expirations;i++)
                RunTimeWheel();
        }
        //辅助接口，确保添加定时任务在同一个线程（一个线程一个eventloop）里执行
        void AddTimeTaskInLoop(uint64_t id,uint32_t delay,const Func_Task_Callback &callback)//添加定时任务(先封装后添加)
        {
            //先封装
            Shared_Ptr_TimeTask task = std::make_shared<TimeTask>(id,delay,callback);
            task->SetRemoveCallback(std::bind(&TimeWheel::RemoveTimeTaskFromMap,this,id));//设置移除回调函数(从map中移除)
            int p  = (_pos+delay)%_size;
            // std::cout<<_pos<<std::endl;
            _wheel[p].push_back(task);//添加到时间轮中
            _time_task_map[id] = Weak_Ptr_TimeTask(task);//添加到map中

        }
        void DelayTimeTaskInLoop(uint64_t id)//刷新任务(重新添加到时间轮中，增加shared_ptr引用计数，以达到延时效果)
        {
            auto it = _time_task_map.find(id);
            if(it == _time_task_map.end())
                return;
            Shared_Ptr_TimeTask task = it->second.lock();//通过weak_ptr获取到shared_ptr指向的任务(增加引用计数，\
            而不是用另一个shared_ptr指向如果用另一个shared_ptr指向，则可能会内存泄漏)
            // std::cout<<"before usecount "<<task.use_count()<<std::endl;
            if(!task)//任务被释放了
                return;
            int delaytime = task->GetDelay();
            int p  = (_pos+delaytime)%_size;
            _wheel[p].push_back(task);//重新添加到时间轮中(以达到延迟的效果)
            // std::cout<<"after usecount "<<task.use_count()<<std::endl;
        }
        void CancelTimeTaskInLoop(uint64_t id)//取消定时任务
        {
            // std::cout<<"cancel task "<<id<<std::endl;
            auto it = _time_task_map.find(id);
            if(it == _time_task_map.end())
                return;
            Shared_Ptr_TimeTask task = it->second.lock();
            if(!task)
                return;
            task->SetCanceled();
        }
    public:
        TimeWheel(EventLoop *loop,uint32_t size = 60);
        //确保下面的操作是线程安全的
        void AddTimeTaskOneThread(uint64_t id,uint32_t delay,const Func_Task_Callback &callback);
        void DelayTimeTaskOneThread(uint64_t id);
        void CancelTimeTaskOneThread(uint64_t id);

        void RunTimeWheel()//运行时间轮(这个应该每秒钟运行一次)
        {
            _pos = (_pos+1)%_size;
            if(_wheel[_pos].empty())//当前指针位置没有任务
                return;
            // std::cout<<"before "<<_wheel[_pos][0].use_count()<<std::endl;
            _wheel[_pos].clear();//清空当前指针位置的任务(usecount = 0自动析构，从而执行任务的回调函数)
            // std::cout<<"after "<<_wheel[_pos][0].use_count()<<std::endl;
        }
        
        int GetPos(){ return _pos; }//获取当前指针位置
        
        /*这个接⼝存在线程安全问题--这个接⼝实际上不能被外界使⽤者调⽤，只能在模块内，在对应的EventLoop线程内执⾏*/
        bool IsExistTimeTask(uint64_t id)//判断是否有id对应的任务
        {
            return _time_task_map.find(id)!= _time_task_map.end();
        }
        
        int GetMapSize()//获取任务数量iu7
        {
            return _time_task_map.size();
        }
};


//one thread one eventloop ：EventLoop模块
class EventLoop {
    private:
        using Func_t = std::function<void()>;
        Poller _epoll;//进⾏所有描述符的事件监控
        TimeWheel _timewheel;//时间轮（管理所有定时任务TimeTask）
        std::thread::id _thread_id;//线程id（一个EventLoop一个线程）
        int _eventfd;//eventfd唤醒IO时间监控
        std::unique_ptr<Channel> _eventfd_channel;//eventfd对应的channel
        std::vector<Func_t> _tasks;//任务队列
        std::mutex _mutex;//互斥锁,保护任务队列操作的线程安全
    public:
        void RunAllTasks()//执行任务队列中的所有任务
        {
            std::vector<Func_t> tasks;
            {
                std::unique_lock<std::mutex> lock(_mutex);//直接加锁
                tasks.swap(_tasks);//将任务队列中的任务移动到tasks中
            }
            for(auto &task : tasks){
                task();
            }
        }
        void ReadEventfd()//读取eventfd,让其事件清零，避免重复唤醒
        {
            uint64_t value;
            ssize_t n = read(_eventfd, &value, sizeof(value));
            if(n < 0){
                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR){
                    LOG_ERR("read eventfd failed %s",strerror(errno));
                    exit(1);
                }
            }
        }
        void WriteEventfd()//写入eventfd,通知IO事件监控
        {
            uint64_t value = 1;
            // std::cout<<_eventfd<<std::endl;
            ssize_t n = write(_eventfd,&value, sizeof(uint64_t));
            if(n < 0){
                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR){
                    LOG_ERR("write eventfd failed %s",strerror(errno));
                    exit(1);
                }
            }
        }
    public:
        EventLoop()
            :_thread_id(std::this_thread::get_id())
            ,_timewheel(this)   
        {
            _eventfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);//创建eventfd
            if(_eventfd < 0){
                LOG_ERR("create eventfd failed %s",strerror(errno));
                exit(1);
            }
            LOG_INF("create eventfd %d",_eventfd);
            _eventfd_channel = std::make_unique<Channel>(this,_eventfd);
            // _eventfd_channel->GetLoop()->AddEvent(_eventfd_channel.get());//添加eventfd对应的channel到epoll中
            this->AddEvent(_eventfd_channel.get());//添加eventfd对应的channel到epoll中
            _eventfd_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd,this));
            _eventfd_channel->EnableReading();//启动eventfd的读事件监控
            this->ModifyEvent(_eventfd_channel.get());//修改eventfd对应的channel的事件类型为读事件
        }
        bool IsInLoop()//判断是否是当前线程是否是EventLoop对应的线程
        {
            //std::this_thread::get_id()获取当前线程id
            //_thread_id是EventLoop对应的线程id
            return std::this_thread::get_id() == _thread_id;
        }
        
        void AddTaskInLoop(const Func_t &cb)//将操作放入任务队列（放到eventloop的任务队列中）
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _tasks.push_back(cb);
            }
            //唤醒有可能因为没有事件就绪而导致的epoll阻塞（本质就是给eventfd写入数据，eventfd就会触发epoll的读事件）
            WriteEventfd();
        }
        void RuninLoop(const Func_t &cb)//先判断任务是否在当前线程中，如果不是，则将任务放入任务队列，是则直接执行
        {
            if(IsInLoop()){
                cb();
            }else{
                AddTaskInLoop(cb);
            }
        }
        
        void AddEvent(Channel* channel) {_epoll.AddChannel(channel);}
        void RemoveEvent(Channel* channel) { _epoll.DelChannel(channel);}
        void ModifyEvent(Channel* channel) {_epoll.ModifChannel(channel);}
        bool HasEvent(Channel* channel) { return _epoll.IsExistChannel(channel);}

        void Start()//启动EventLoop
        {
            //1.事件监控
            std::vector<Channel *> active;//用于获取就绪事件的channel
            _epoll.WaitEventsFromChannels(&active);
            //2.就绪事件处理
            for(auto &channel: active){
                channel->HandleEvent();
            }
            //3.执行任务
            RunAllTasks();
        }
        //EventLoop中的定时任务接口（调用成员变量_timewheel的接口）
        void AddTimeTask(uint64_t id,uint32_t delay,const Func_Task_Callback &callback)
        {
            _timewheel.AddTimeTaskOneThread(id,delay,callback);
        }

        void DelayTimeTask(uint64_t id)
        {
            _timewheel.DelayTimeTaskOneThread(id);
        }

        void CancelTimeTask(uint64_t id)
        {
            _timewheel.CancelTimeTaskOneThread(id);
        }
        bool HasTimeTask(uint64_t id)
        {
            return _timewheel.IsExistTimeTask(id);
        }

};

TimeWheel::TimeWheel(EventLoop *loop,uint32_t size):_loop(loop),_size(size),_pos(0),_wheel(_size)
{
    _timerfd = timerfd_create(CLOCK_MONOTONIC,0);//阻塞式定时器
    LOG_INF("create timerfd %d",_timerfd);
    if(_timerfd == -1){
        LOG_ERR("create timerfd error");
        abort();
    }
    struct itimerspec its;
    its.it_value.tv_sec = 1;//第一次到期时间为1s后
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;//间隔时间为1s
    its.it_interval.tv_nsec = 0;
    int ret = timerfd_settime(_timerfd,0,&its,NULL);
    if(ret == -1){
        LOG_ERR("set timerfd error");
        close(_timerfd);
        abort();
    }
    _timefd_channel = std::make_unique<Channel>(_loop, _timerfd);//封装的_timerfd
    _loop->AddEvent(_timefd_channel.get());//将定时器fd放入epoll监控
    _timefd_channel->SetReadCallback(std::bind(&TimeWheel::OnTimefdEvent,this));//设置定时器事件发生的回调函数
    _timefd_channel->EnableReading();//启动读事件监控（每隔规定的时间间隔触发一次超时事件）
    _loop->ModifyEvent(_timefd_channel.get());//将定时器fd的读事件放入epoll监控

}

void TimeWheel::AddTimeTaskOneThread(uint64_t id,uint32_t delay,const Func_Task_Callback &callback)
{
    _loop->RuninLoop(std::bind(&TimeWheel::AddTimeTaskInLoop,this,id,delay,callback));
}

void TimeWheel::DelayTimeTaskOneThread(uint64_t id)
{
    _loop->RuninLoop(std::bind(&TimeWheel::DelayTimeTaskInLoop,this,id));
}

void TimeWheel::CancelTimeTaskOneThread(uint64_t id)
{
    _loop->RuninLoop(std::bind(&TimeWheel::CancelTimeTaskInLoop,this,id));
}